package com.knife.service;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.context.Context;
import org.apache.velocity.io.VelocityWriter;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;

import cn.com.cjf.CJFBeanFactory;
import cn.com.cjf.ChineseJF;

import com.knife.news.logic.NewsService;
import com.knife.news.logic.SiteService;
import com.knife.news.logic.TreeService;
import com.knife.news.logic.TypeService;
import com.knife.news.logic.impl.NewsServiceImpl;
import com.knife.news.logic.impl.SiteServiceImpl;
import com.knife.news.logic.impl.TreeServiceImpl;
import com.knife.news.logic.impl.TypeServiceImpl;
import com.knife.news.object.News;
import com.knife.news.object.Site;
import com.knife.news.object.Type;
import com.knife.util.CommUtil;
import com.knife.web.Globals;
import com.knife.web.RequestProcessor;
import com.knife.web.tools.CommTool;

/**
 * HTML生成类
 * @author Knife
 *
 */
public class HTMLGenerater {
	private String baseDir;
	private static final Logger logger = Logger
			.getLogger(RequestProcessor.class.getName());
	private static SiteService siteDAO = SiteServiceImpl.getInstance();
	private static NewsService newsDAO = NewsServiceImpl.getInstance();
	private static TypeService typeDAO = TypeServiceImpl.getInstance();
	private static TreeService treeDAO = TreeServiceImpl.getInstance();
	private Site site;
	private Type type;
	private News news;
	private VelocityFactory vf = new VelocityFactory();
	private File file;
	private File big5file;
	private String fileName;
	private String templateName;
	private Template template;
	static ChineseJF chinesdJF;
	static List<Type> nav;

	public HTMLGenerater() {
		site = siteDAO.getSite();
		this.baseDir = Globals.APP_BASE_DIR;
	}

	public HTMLGenerater(String siteid) {
		site = siteDAO.getSiteById(siteid);
		this.baseDir = Globals.APP_BASE_DIR;
		// System.out.println("站点模板文件夹为:"+site.getPub_dir());
	}

	public String getTemplatePath() {
		String path = Globals.APP_BASE_DIR + "WEB-INF/templates/web/";
		if (path.indexOf('/') > 0) {
			path = path.replace('/', File.separatorChar);
		}
		return path;
	}

	public String getSysTemplate() {
		String path = Globals.APP_BASE_DIR + "WEB-INF/templates/sys/";
		if (path.indexOf('/') > 0) {
			path = path.replace('/', File.separatorChar);
		}
		return path;
	}

	private void addCommonContext(Context context) {
		context.put("thisSite", site);
		context.put("newsDAO", newsDAO);
		context.put("typeDAO", typeDAO);
		if (site != null){
			nav = typeDAO.getSubTypesById(site.getId(), "0", 1);
		}
		context.put("nav", nav);
		CommTool.createUtilContext(context);
	}

	/**
	 * 生成网站首页
	 * 
	 * @return
	 */
	public boolean saveIndexToHtml() {
		Context context = new VelocityContext();
		addCommonContext(context);
		fileName = "index.htm";
		if(site.getIndex()!=null){
			if(site.getIndex().length()>0){
				fileName = site.getIndex();
			}
		}
		file = new File(baseDir + "html/" + site.getPub_dir() + "/"
				+ fileName);
		if (!(file.getParentFile().exists())) {
			file.getParentFile().mkdirs();
		}
		templateName = "index.htm";
		template = vf.getTemplate(site.getTemplate(), templateName, "utf-8");
		mergeTemplate(template, context, file);
		System.out.println("generate index:"+file.getAbsolutePath());
		//发布准备
		HTMLPublish.pub(file, "/" + site.getPub_dir() + "/");
		// 如果要生成繁体站
		if (site.getBig5() > 0) {
			chinesdJF = CJFBeanFactory.getChineseJF();
			big5file = new File(baseDir + "html/" + site.getPub_dir()
					+ "/big5/" + fileName);
			if (!(big5file.getParentFile().exists())) {
				big5file.getParentFile().mkdirs();
			}
			try {
				if (!file.getAbsolutePath().equals(big5file.getAbsolutePath())) {
					//chinesdJF.chineseJan2Fan(file, "UTF-8", big5file, "UTF-8");
					if(big5file.exists()){
						big5file.delete();
					}
					big5file.createNewFile();
					if(big5file.canWrite()){
						chinesdJF.chineseJan2Fan(file, "UTF-8", big5file, "UTF-8");
					}
				}
			} catch (Exception e) {
				System.out.println("简繁转换错误:" + e.getMessage());
			}
			//发布准备
			HTMLPublish.pub(big5file, "/" + site.getPub_dir() + "/");
		}
		return true;
	}

	/**
	 * 生成所有频道
	 * 
	 * @return
	 */
	public boolean saveAllTypesToHtml() {
		List<Type> types = typeDAO.getAllTypes(1);
		for (Type atype : types) {
			saveTypeIndexToHtml(atype.getId());
		}
		return true;
	}

	/**
	 * 生成所有文章
	 * 
	 * @return
	 */
	public boolean saveAllNewsToHtml() {
		List<Type> types = typeDAO.getAllTypes(1);
		for (Type atype : types) {
			List<News> news = newsDAO.getNewsByType(atype.getId());
			for (News anews : news) {
				saveNewsToHtml(anews.getId());
			}
		}
		return true;
	}

	public boolean deleteHtml(String nid){
		String fileName = "";
		String datedir = "";
		try{
			news = newsDAO.getNewsById(nid);
			type = typeDAO.getTypeById(news.getType());
			site = siteDAO.getSiteById(type.getSite());
		}catch(Exception e){}
		if (site.getHtml_dir() == 0) {
			datedir = news.getNewsYear() + "/";
		} else if (site.getHtml_dir() == 1) {
			datedir = news.getNewsYear() + "/"
					+ news.getNewsMonth() + "/";
		} else {
			datedir = news.getNewsYear() + "/"
					+ news.getNewsMonth() + "/"
					+ news.getNewsDay() + "/";
		}
		if (site.getHtml_rule() == 0) {
			fileName = type.getTypeNamePath() + "/" + datedir
					+ Jsoup.clean(news.getTitle(), Whitelist.simpleText())
					+ ".htm";
		}else if(site.getHtml_rule() == 1){
			fileName = type.getTypeCNSpellPath() + "/" + datedir + news.getCNSpellTitle()
					+ ".htm";
		} else {
			fileName = type.getTypeIdPath() + "/" + datedir + news.getId()
					+ ".htm";
		}
		File file = new File(baseDir + "html/" + site.getPub_dir() + fileName);
		HTMLPublish.unpub(file, "/" + site.getPub_dir() + "/");
		if (file.exists()) {
			file.delete();
		}
		return true;
	}
	
	/**
	 * 生成文章
	 * 
	 * @param nid
	 * @return String
	 * @throws Exception
	 */
	public boolean saveNewsToHtml(String nid) {
		Context context = new VelocityContext();
		News news = newsDAO.getNewsById(nid);
		context.put("thisNews", news);
		Type type=new Type();
		if(news.getType()!=null){
			type = typeDAO.getTypeById(news.getType());
			context.put("thisType", type);
			site = siteDAO.getSiteById(type.getSite());
		}
		addCommonContext(context);
		String fileName = "";
		String datedir = "";
		if (site.getHtml_dir() == 0) {
			datedir = news.getNewsYear() + "/";
		} else if (site.getHtml_dir() == 1) { 
			datedir = news.getNewsYear() + "/"
					+ news.getNewsMonth() + "/";
		} else {
			datedir = news.getNewsYear() + "/"
					+ news.getNewsMonth() + "/"
					+ news.getNewsDay() + "/";
		}
		if (site.getHtml_rule() == 0) {
			fileName = type.getTypeNamePath() + "/" + datedir
					+ Jsoup.clean(news.getTitle(), Whitelist.simpleText())
					+ ".htm";
		} else if (site.getHtml_rule() == 1){
			fileName = type.getTypeIdPath() + "/" + datedir + news.getId()
					+ ".htm";
		}else{
			fileName = type.getTypeCNSpellPath() + "/" + datedir + news.getCNSpellTitle()
					+ ".htm";
		}
		file = new File(baseDir + "html/" + site.getPub_dir() + fileName);
		if (!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		templateName = type.getNews_template();
		template = vf.getTemplate(site.getTemplate(), templateName, "utf-8");
		mergeTemplate(template, context, file);
		System.out.println("generate news:"+file.getAbsolutePath());
		//发布准备
		HTMLPublish.pub(file, "/" + site.getPub_dir() + "/");
		//如果要生成繁体站
		if (site.getBig5() > 0) {
			ChineseJF chinesdJF = CJFBeanFactory.getChineseJF();
			big5file = new File(baseDir + "html/" + site.getPub_dir()
					+ "/big5/" + fileName);
			if (!(big5file.getParentFile().exists())) {
				big5file.getParentFile().mkdirs();
			}
			try {
				if (!file.getAbsolutePath().equals(big5file.getAbsolutePath())) {
					if(big5file.exists()){
						big5file.delete();
					}
					big5file.createNewFile();
					if(big5file.canWrite()){
						chinesdJF.chineseJan2Fan(file, "UTF-8", big5file, "UTF-8");
					}
				}
			} catch (Exception e) {
				System.out.println("简繁转换错误:" + e.getMessage());
			}
			//发布准备
			HTMLPublish.pub(big5file, "/" + site.getPub_dir() + "/");
		}
		//如果文章下包含分类树
		if(CommUtil.null2String(type.getTree()).length()>0){
			List<Type> treeTypes=typeDAO.getTreeTypesByTypeID(type.getId(), 1);
			List<News> allNews = new ArrayList<News>();
			Collection<Object> paras;
			String sql;
			int rows;
			int pageSize;
			int totalPage;
			int nowPage;
			for(Type gtype:treeTypes){
				if(gtype!=null){
					paras = new ArrayList<Object>();
					paras.add(gtype.getId());
					sql = "k_display='1' and k_ispub='1' and k_type=? order by length(k_order) desc,k_order desc";
					allNews = newsDAO.getNews(sql, paras);
					for (News anews : allNews) {
						saveNewsToHtml(anews.getId());
					}
					rows = allNews.size();// 总数
					pageSize = CommUtil.null2Int(gtype.getPagenum());// 每页20条
					totalPage = (int) Math.ceil((float) (rows) / (float) (pageSize));// 计算页数
					if (totalPage < 1) {
						totalPage = 1;
					}
					for (int i = 0; i < totalPage; i++) {
						nowPage = i + 1;
						saveTreeTypeListToHtml(gtype.getId(),nid, sql, paras, nowPage, rows);
					}
					System.out.println("generate:" + gtype.getName() + ":" + gtype.getHref());
				}
			}
		}
		return true;
	}
	
	public boolean saveTypeIndexToHtml(String tid) {
		//generate parent types
		List<Type> types=typeDAO.getAllParentTypesById(tid);
		if(types.size()>0){
			for(Type atype:types){
				if(atype!=null){
					saveTypeIndexToHtml(atype.getId(),"");
				}
			}
		}
		return saveTypeIndexToHtml(tid,"");
	}

	//生成频道首页
	public boolean saveTypeIndexToHtml(String tid,String treenews) {
		Type type = typeDAO.getTypeById(tid);
		/*String templateName = type.getType_template();
		if (!CommUtil.hasLength(templateName)) {
			templateName = "list.htm";
		}*/
		if(type.getUrl()!=null){
			if(type.getUrl().length()>0){
				return true;
			}
		}
		if(type.getShow()==1){
			templateName = type.getNews_template();
		}else{
			templateName = type.getType_template();
		}
		Collection<Object> paras = new ArrayList<Object>();
		paras.add(tid);
		String sql="k_display='1' and k_ispub='1' and k_type=?";
		if(treenews.length()>0){
			paras.add(treenews);
			sql+=" and k_treenews=?";
		}
		sql+=" order by length(k_order) desc,k_order desc";
		//int rows = newsDAO.getSum(1, "", sql, tid, treenews, "", "");
		int rows = newsDAO.getSum(1, "",type.getSite(), tid, treenews, "","",1);
		return saveToHtml(templateName, baseDir + type.getHref(1), type, sql, paras,rows, 1);
		/*
		int pageSize = CommUtil.null2Int(type.getPagenum());
		if(pageSize<=0){pageSize=20;}
		int totalPage=(int) Math.ceil((float)rows/ (float) pageSize);
		if(totalPage<=0){totalPage=1;}
		for(int i=1;i<=totalPage;i++){
			String fileName = type.getHref(i);
			String filePath = baseDir + fileName;
			saveToHtml(templateName, filePath, type, sql, paras,rows, i);
		}
		*/
		//System.out.println("generate:"+type.getName()+":"+type.getHref());
	}
	
	/**
	 * 生成频道列表页
	 * 
	 * @param tid
	 *            频道ID
	 * @param page
	 *            页码
	 * @return
	 */
	public boolean saveTreeTypeListToHtml(String tid, String nid,String sql,
			Collection<Object> paras, int page,int rows) {
		Type type = typeDAO.getTypeById(tid);
		if(type.getUrl()!=null){
			if(type.getUrl().length()>0){
				return true;
			}
		}
		if(type.getShow()==1){
			templateName = type.getNews_template();
		}else{
			templateName = type.getType_template();
		}
		if (!CommUtil.hasLength(templateName)) {
			templateName = "list.htm";
		}
		type.setSite(site.getId());
		type.setTreenews(nid);
		String fileName = type.getHref(page);
		String filePath = baseDir + fileName;
		//int rows = newsDAO.getSum(1, "", sql, tid, "", "", "");
		if(rows<0){
			rows = newsDAO.getSum(1, "",type.getSite(), tid, "", "","",1);
		}
		//System.out.println("生成路径:" + filePath);
		return saveToHtml(templateName, filePath, type, sql, paras,rows, page);
	}
	
	public boolean saveTypeListToHtml(String tid, String sql,
			Collection<Object> paras, int page) {
		return saveTypeListToHtml(tid, sql, paras, page,-1);
	}

	/**
	 * 生成频道列表页
	 * 
	 * @param tid
	 *            频道ID
	 * @param page
	 *            页码
	 * @return
	 */
	public boolean saveTypeListToHtml(String tid, String sql,
			Collection<Object> paras, int page,int rows) {
		Type type = typeDAO.getTypeById(tid);
		if(type.getUrl()!=null){
			if(type.getUrl().length()>0){
				return true;
			}
		}
		if(type.getShow()==1){
			templateName = type.getNews_template();
		}else{
			templateName = type.getType_template();
		}
		if (!CommUtil.hasLength(templateName)) {
			templateName = "list.htm";
		}
		String fileName = type.getHref(page);
		String filePath = baseDir + fileName;
		//int rows = newsDAO.getSum(1, "", sql, tid, "", "", "");
		if(rows<0){
			rows = newsDAO.getSum(1, "",type.getSite(), tid, "", "","",1);
		}
		//System.out.println("生成路径:" + filePath);
		return saveToHtml(templateName, filePath, type, sql, paras,rows, page);
	}

	/*
	 * 静态化的公共方法
	 */
	private boolean saveToHtml(String templateName, String filePath, Type type,
			String sql, Collection<Object> paras,int rows, int page) {
		Context context = new VelocityContext();
		List<News> list = newsDAO.getNews(sql, paras);
		int pageSize = Integer.parseInt(type.getPagenum());
		if (pageSize <= 0) {
			pageSize = 20;
		}
		int currentPage = page;
		int totalPage = (int) Math.ceil((float) rows / (float) pageSize);
		if (currentPage < 1) {
			currentPage = 1;
		}
		if (currentPage > totalPage) {
			currentPage = totalPage;
		}
		int frontPage = currentPage - 1;
		int nextPage = currentPage + 1;
		if (nextPage > totalPage) {
			nextPage = totalPage;
		}
		int begin = (currentPage - 1) * pageSize;
		if(begin<0){begin=0;}
		int end = begin+pageSize;
		if(end>rows){
			end=rows;
		}
		if(end>list.size()){
			end=list.size();
		}
		List<News> pageList = list;
		if(end>0){
			pageList = list.subList(begin, end);
		}
		context.put("currentPage", currentPage);
		context.put("totalPage", totalPage);
		context.put("pageSize", pageSize);
		context.put("frontPage", frontPage);
		context.put("nextPage", nextPage);
		context.put("rows", rows);
		context.put("newsList", pageList);
		context.put("thisType", type);
		News news = new News();
		if(rows>0){
			news = (News) newsDAO.getTopNews(type.getId(), 1).get(0);
		}
		context.put("thisNews", news);
		addCommonContext(context);
		File file = new File(filePath);
		if (!(file.getParentFile().exists())) {
			file.getParentFile().mkdirs();
		}
		// 替换链接
		if (site != null){
		template = vf.getTemplate(site.getTemplate(), templateName, "utf-8");
		
		mergeTemplate(template, context, file);
		System.out.println("generate:"+file);
		//发布准备
		HTMLPublish.pub(file, "/" + site.getPub_dir() + "/");
		// 如果要生成繁体站
		if (site.getBig5() > 0) {
			ChineseJF chinesdJF = CJFBeanFactory.getChineseJF();
			big5file = new File(filePath.replace(
					"html/" + site.getPub_dir() + "/",
					"html/" + site.getPub_dir() + "/big5/"));
			if (!(big5file.getParentFile().exists())) {
				big5file.getParentFile().mkdirs();
			}
			try {
				if (!file.getAbsolutePath().equals(big5file.getAbsolutePath())) {
					if(big5file.exists()){
						big5file.delete();
					}
					big5file.createNewFile();
					if(big5file.canWrite()){
						chinesdJF.chineseJan2Fan(file, "UTF-8", big5file, "UTF-8");
					}
				}
			} catch (Exception e) {
				System.out.println("简繁转换错误:" + e.getMessage());
			}
			//发布准备
			HTMLPublish.pub(big5file, "/" + site.getPub_dir() + "/");
		}
		}
		return true;
	}

	public String mergeFile(String mainFile, String contentFile,
			String[] navigatFile) {
		String main = file2String(new String[] { mainFile });
		String content = file2String(new String[] { contentFile });
		String navigate = file2String(navigatFile);
		main = main.replace("${content}", content);
		main = main.replace("${navigate}", navigate);
		return main;
	}

	public String file2String(String[] filename) {
		StringBuffer buffer = new StringBuffer();
		BufferedReader reader = null;
		String[] arrayOfString = filename;
		int i = 0;
		for (int j = arrayOfString.length; i < j;) {
			String str = arrayOfString[i];
			try {
				reader = new BufferedReader(new FileReader(str));
				loadString(buffer, reader);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} finally {
				if (reader != null)
					try {
						reader.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
			}
			++i;
		}
		return buffer.toString();
	}

	protected void loadString(StringBuffer buffer, BufferedReader br) {
		try {
			String str;
			while ((str = br.readLine()) != null)
				buffer.append(str + "\n");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	protected void mergeTemplate(Template template, Context context,
			File file) {
		Writer writer=null;
		VelocityWriter vw=null;
		try {
			writer = new OutputStreamWriter(new FileOutputStream(file), template.getEncoding());
			vw = new VelocityWriter(writer, 10240, true);
			template.merge(context, vw);
		} catch (Exception e) {
			logger.error("合成错误：模板错误" + e);
			//throw new NullPointerException("模板错误:" + e.getMessage());
		} finally {
			if (vw != null) {
				try {
					//vw.flush();
					vw.close();
					writer.close();
				} catch (Exception e) {
					//logger.error(e.getMessage());
					//e.printStackTrace();
				}
			}
		}
	}
}